<script setup lang="ts">
import { createForm, onFieldInputValueChange } from '@formily/core';
import {
  Form,
  FormItem,
  FormLayout,
  Input,
  InputNumber,
  Select,
} from '@formily/element-plus';
import { createSchemaField } from '@formily/vue';
import { GlobalRegistry } from '@season-designable/core';
import { cancelIdle, requestIdle } from '@season-designable/shared';
import {
  NodePathWidget,
  useBehaviorSubject,
  useOperation,
  usePrefix,
  useSelection,
  useTree,
  useWorkbench,
} from '@season-designable/vue';
import { cloneDeep, each, get, isString, set } from 'lodash-es';
import BackgroundStyleSetter from './components/BackgroundStyleSetter/index.vue';
import BorderStyleSetter from './components/BorderStyleSetter/index.vue';
import BoxShadowStyleSetter from './components/BoxShadowStyleSetter/index.vue';
import BoxStyleSetter from './components/BoxStyleSetter/index.vue';
import CollapseItem from './components/CollapseItem/index.vue';
import DisplayStyleSetter from './components/DisplayStyleSetter/index.vue';
import FontStyleSetter from './components/FontStyleSetter/index.vue';
import IconSetter from './components/IconSetter/index.vue';
import PositionInput from './components/PositionInput/index.vue';
import Rate from './components/Rate';
import SizeInput from './components/SizeInput/SizeInput.vue';
import ValueOnClearInput from './components/SizeInput/ValueOnClearInput.vue';
import Slider from './components/Slider';
import Switch from './components/Switch';

const props = defineProps(['components']);
const components = {
  FormItem,
  Input,
  Switch,
  InputNumber,
  Slider,
  Rate,
  Select,
  CollapseItem,
  SizeInput,
  DisplayStyleSetter,
  BackgroundStyleSetter,
  BoxShadowStyleSetter,
  FontStyleSetter,
  BoxStyleSetter,
  BorderStyleSetter,
  IconSetter,
  PositionInput,
  ValueOnClearInput,
  ...props.components,
};

const { SchemaField } = createSchemaField({
  components,
});

let timeRequest: any = null;

const prefix = usePrefix('settings-form');
const workbench = useWorkbench();
const currentWorkspace =
  workbench?.activeWorkspace || workbench?.currentWorkspace;
const currentWorkspaceId = currentWorkspace?.id;
const operation = useOperation(currentWorkspaceId);
const selection = useSelection(currentWorkspaceId);
const tree = useTree(currentWorkspaceId);
const selected = useBehaviorSubject<any>(selection?.selected);
const node = computed(() => tree?.findById(selected.value[0]));
const langRef = useBehaviorSubject(GlobalRegistry.getDesignerLanguageStore());
const idleTask = ref<number>();

const isEmpty = computed(
  () =>
    !(
      node.value &&
      node.value.designerProps?.propsSchema &&
      selected.value.length === 1
    )
);

const takeMessage = (path: string, prop?: string) => {
  const pathList = Array.from(new Set(path.split('.')));

  if (pathList.length === 1) {
    const token = `settings.${pathList[0]}${prop ? `.${prop}` : ''}`;

    return (
      node.value?.getMessage(token) || GlobalRegistry.getDesignerMessage(token)
    );
  }

  for (let index = 0; index <= pathList.length - 1; index++) {
    let subPath =
      pathList.slice(index, pathList.length - 1).length > 0
        ? pathList.slice(index, pathList.length - 1).join('.') +
          '.' +
          pathList[pathList.length - 1]
        : pathList[pathList.length - 1];

    const token = `settings.${subPath}${prop ? `.${prop}` : ''}`;

    let result =
      node.value?.getMessage(token) || GlobalRegistry.getDesignerMessage(token);

    if (result) {
      return result;
    }
  }

  return '';
};

const setFieldSource = (properties: Record<string, any>, prefix?: string) => {
  let resultProps = properties;

  each(resultProps, (value, key) => {
    const path = prefix ? `${prefix}.${key}` : key;
    if (value.properties) {
      resultProps[key].properties = setFieldSource(value.properties, path);
    }

    const title = takeMessage(path, 'title') || takeMessage(path);

    resultProps[key].title = title;

    const dataSource = takeMessage(path, 'dataSource');

    if (dataSource?.length) {
      resultProps[key].enum = resultProps[key].enum.map(
        (item: any, index: number) => ({
          value: item,
          label: dataSource[index],
        })
      );
    }
  });

  return resultProps;
};

const schema = ref();
const form = ref();

watch(
  [node, langRef],
  () => {
    idleTask.value && cancelIdle(idleTask.value);
    idleTask.value = requestIdle(() => {
      if (!node.value) {
        return;
      }

      let propsSchema = cloneDeep(node.value.designerProps.propsSchema) || {};
      propsSchema.properties = setFieldSource(propsSchema.properties);
      schema.value = propsSchema;

      form.value = createForm({
        // initialValues: node.value.designerProps.defaultProps,
        values: {
          name: node.value.id,
          ...node.value.designerProps.defaultProps,
          ...node.value?.props.value,
        },
        effects() {
          // if (!init.value) {
          //   onFormMount((form) => {
          //     init.value = true;
          //   });
          // } else {
          // onFormValuesChange((form) => {
          //   node.value?.props.next({
          //     ...node.value?.props.value,
          //     ...JSON.parse(JSON.stringify(form.values)),
          //     // ...cloneDeep(form.values),
          //   });
          // });

          onFieldInputValueChange('*', (field) => {
            const path = field.path.entire;
            const nodeProps: Record<string, any> = JSON.parse(
              JSON.stringify(node.value?.props.value)
            );

            if (
              nodeProps &&
              isString(path) &&
              get(nodeProps, path) !== field.value
            ) {
              set(nodeProps, path, field.value);
              node.value?.props.next(nodeProps);

              clearTimeout(timeRequest);
              timeRequest = setTimeout(() => {
                operation?.snapshot('updateNodeProps');
              }, 500);
            }
          });
          // }
        },
      });
    });
  },
  { immediate: true }
);
</script>

<template>
  <div :class="prefix + '-wrapper'">
    <NodePathWidget v-if="!isEmpty" :workspaceId="currentWorkspaceId" />
    <div :class="prefix + '-content'">
      <div :class="prefix" v-if="form">
        <Form :form="form" :key="form?.id">
          <FormLayout
            :colon="false"
            :labelCol="9"
            :wrapperCol="15"
            labelAlign="left"
            wrapperAlign="right"
            tooltipLayout="text"
            feedbackLayout="none"
          >
            <SchemaField :schema="schema" :scope="{ $node: node }" />
          </FormLayout>
        </Form>
      </div>
    </div>
  </div>
</template>

<style lang="scss" scoped>
@import '../../styles.scss';

@keyframes fadeIn {
  0% {
    opacity: 0;
  }

  100% {
    opacity: 1;
  }
}

@keyframes slideInRight {
  0% {
    transform: translateX(100%);
  }

  100% {
    transform: translateX(0);
  }
}

@keyframes slideOutRight {
  0% {
    transform: translateX(0);
  }

  100% {
    transform: translateX(100%);
  }
}

.animate__slideInRight {
  -webkit-animation-name: slideInRight;
  animation-name: slideInRight;
}

.animate__slideOutRight {
  -webkit-animation-name: slideOutRight;
  animation-name: slideOutRight;
}

.animate__animated {
  animation-delay: 0ms;
  animation-duration: 0.25s;
  animation-fill-mode: forwards;
}

.animate__fadeInUp {
  -webkit-animation-name: fadeIn;
  animation-name: fadeIn;
}

.dn-settings-form-wrapper {
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  overflow: hidden;

  .dn-node-path {
    flex-grow: 0;
  }

  .dn-settings-form-content {
    flex-grow: 1;
    overflow: overlay;
  }

  :deep(.#{$formily-element-prefix}-form-item) {
    border-bottom: 1px solid #{$border-color-split};
    padding-bottom: 8px;
    margin-bottom: 8px;
    margin-top: 8px;

    * {
      font-size: 13px;
    }

    .#{$formily-element-prefix}-form-item-control-content-component {
      display: flex;
      align-items: center;
      justify-content: flex-end;

      & > .#{$formily-element-prefix}-radio-group {
        display: flex !important;
        width: 100%;

        .#{$formily-element-prefix}-radio-button-wrapper {
          display: flex;
          justify-content: center;
          padding: 0 6px !important;
          align-items: center;
          flex-grow: 2;
        }
      }

      & > .#{$formily-element-prefix}-slider {
        flex-shrink: 0;
        min-width: 0;
        width: 100%;
      }

      & > .#{$formily-element-prefix}-select {
        max-width: 140px;
      }
    }
  }
}

.dn-settings-form {
  padding: 0 20px;

  &-empty {
    display: flex;
    align-items: center;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    color: #888;
  }
}
</style>
